//
// Created on 2025/7/21.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".

#ifndef STREAMCORE_TASK_QUEUE_H
#define STREAMCORE_TASK_QUEUE_H
#include <functional>
#include <napi/native_api.h>
#include <thread>

class TaskQueue {
public:
    using Task = std::function<void(napi_env)>;
    using Callback = std::function<void(void *)>;
    using Func = std::function<void(napi_env, void *)>;

    TaskQueue() : tid_(), env_(nullptr), tsfn_(nullptr) {}
    TaskQueue(napi_env env) : tid_(), env_(env), tsfn_(nullptr) {
        try {
            init(env);
            tid_ = std::this_thread::get_id();
        } catch (...) {
            if (tsfn_)
                napi_release_threadsafe_function(tsfn_, napi_tsfn_release);
            throw; // 重新抛出异常
        }
    }

    TaskQueue(TaskQueue &&other) noexcept : tid_(other.tid_), env_(other.env_), tsfn_(other.tsfn_) {
        other.tsfn_ = nullptr; // 防止重复释放
    }

    TaskQueue &operator=(TaskQueue &&) = delete;
    TaskQueue(const TaskQueue &) = delete;
    TaskQueue &operator=(const TaskQueue &) = delete;

    ~TaskQueue() {
        if (tsfn_ != nullptr) {
            napi_release_threadsafe_function(tsfn_, napi_tsfn_release);
            tsfn_ = nullptr;
        }
    }

    void init(napi_env env) {
        if (tsfn_ != nullptr) {

            throw std::runtime_error("TaskQueue already initialized");
        }
        napi_value resource_name;
        napi_create_string_utf8(env, "TaskQueue", NAPI_AUTO_LENGTH, &resource_name);
        napi_status status = napi_create_threadsafe_function(env, nullptr, nullptr, resource_name, 0, 1, nullptr,
                                                             nullptr, nullptr, TaskCallback, &tsfn_);

        if (status != napi_ok) {
            throw std::runtime_error(ERR_INIT_ASYNC_TASK_QUEUE_FAILED);
        }
    }


    void enqueue(Func task, void *data = nullptr, Callback callback = nullptr,
                 napi_threadsafe_function_call_mode mode = napi_tsfn_nonblocking) {
        // 主线程直接同步执行
        if (std::this_thread::get_id() == tid_) {
            task(env_, data);
            if (callback)
                callback(data);
            return;
        }

        // 工作线程投递任务
        auto task_wrapper = new TaskWrap(task, data, callback);
        napi_acquire_threadsafe_function(tsfn_);
        napi_status status = napi_call_threadsafe_function(tsfn_, task_wrapper, mode);
        if (status != napi_ok) {
            delete task_wrapper;
            throw std::runtime_error("Failed to call threadsafe function");
        }
    }

private:
    static constexpr auto ERR_INIT_ASYNC_TASK_QUEUE_FAILED = "initialize AsyncTaskQueue failed";
    struct TaskBase {
        virtual ~TaskBase() = default;
        virtual void Execute(napi_env env) = 0;
    };

    struct TaskWrap : TaskBase {

        Func task;
        void *data;
        Callback callback;

        TaskWrap(Func f, void *d, Callback cb) : task(std::move(f)), data(d), callback(std::move(cb)) {}

        void Execute(napi_env env) override {
            task(env, data);
            if (callback) {
                callback(data);
            }
        }
    };


    static void TaskCallback(napi_env env, napi_value js_callback, void *context, void *data) {
        (void)js_callback;
        (void)context;

        auto task = static_cast<TaskBase *>(data);
        if (task) {
            task->Execute(env);
            delete task;
        }
    }


private:
    std::thread::id tid_;
    napi_env env_;
    napi_threadsafe_function tsfn_;
};

#endif // STREAMCORE_TASK_QUEUE_H
